"""
AI模型和预测算法模块
AI Models and Prediction Algorithms Module
"""

import numpy as np
import random
from datetime import datetime, timedelta
from dataclasses import dataclass
from typing import Dict, List, Any, Optional, Tuple
from abc import ABC, abstractmethod
import json
import math
from collections import deque
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, mean_squared_error
import joblib
import os

@dataclass
class PredictionResult:
    """预测结果"""
    model_name: str
    prediction_type: str
    value: Any
    confidence: float
    probability_distribution: Optional[Dict[str, float]]
    explanation: str
    timestamp: datetime
    input_features: Dict[str, Any]

@dataclass
class ModelMetrics:
    """模型性能指标"""
    model_name: str
    accuracy: float
    precision: float
    recall: float
    f1_score: float
    rmse: float
    mae: float
    training_samples: int
    last_updated: datetime

class BaseAIModel(ABC):
    """AI模型基类"""
    
    def __init__(self, name: str):
        self.name = name
        self.is_trained = False
        self.model = None
        self.scaler = None
        self.feature_names = []
        self.training_history = []
        
    @abstractmethod
    def train(self, training_data: List[Dict]) -> bool:
        """训练模型"""
        pass
    
    @abstractmethod
    def predict(self, input_data: Dict) -> PredictionResult:
        """预测"""
        pass
    
    @abstractmethod
    def evaluate(self, test_data: List[Dict]) -> ModelMetrics:
        """评估模型"""
        pass
    
    def save_model(self, file_path: str) -> bool:
        """保存模型"""
        try:
            model_data = {
                'name': self.name,
                'model': self.model,
                'scaler': self.scaler,
                'feature_names': self.feature_names,
                'is_trained': self.is_trained,
                'training_history': self.training_history
            }
            joblib.dump(model_data, file_path)
            return True
        except Exception as e:
            print(f"保存模型失败: {e}")
            return False
    
    def load_model(self, file_path: str) -> bool:
        """加载模型"""
        try:
            model_data = joblib.load(file_path)
            self.name = model_data['name']
            self.model = model_data['model']
            self.scaler = model_data['scaler']
            self.feature_names = model_data['feature_names']
            self.is_trained = model_data['is_trained']
            self.training_history = model_data.get('training_history', [])
            return True
        except Exception as e:
            print(f"加载模型失败: {e}")
            return False

class CropYieldPredictor(BaseAIModel):
    """作物产量预测模型"""
    
    def __init__(self):
        super().__init__("作物产量预测")
        self.model = RandomForestRegressor(n_estimators=100, random_state=42)
        self.scaler = StandardScaler()
        self.feature_names = [
            'avg_temperature', 'avg_humidity', 'avg_soil_moisture',
            'avg_ph', 'avg_nitrogen', 'avg_phosphorus', 'avg_potassium',
            'total_rainfall', 'avg_light_intensity', 'growth_days',
            'irrigation_frequency', 'fertilizer_applications'
        ]
    
    def generate_training_data(self, num_samples: int = 1000) -> List[Dict]:
        """生成训练数据"""
        training_data = []
        
        for _ in range(num_samples):
            # 生成特征数据
            features = {
                'avg_temperature': random.uniform(15, 35),
                'avg_humidity': random.uniform(40, 90),
                'avg_soil_moisture': random.uniform(30, 80),
                'avg_ph': random.uniform(5.5, 8.0),
                'avg_nitrogen': random.uniform(10, 50),
                'avg_phosphorus': random.uniform(5, 25),
                'avg_potassium': random.uniform(15, 40),
                'total_rainfall': random.uniform(0, 500),
                'avg_light_intensity': random.uniform(20000, 80000),
                'growth_days': random.randint(60, 120),
                'irrigation_frequency': random.randint(0, 30),
                'fertilizer_applications': random.randint(0, 10)
            }
            
            # 基于特征计算产量（模拟真实关系）
            base_yield = 100  # 基础产量 kg/亩
            
            # 温度影响
            temp_factor = 1.0
            if 20 <= features['avg_temperature'] <= 28:
                temp_factor = 1.2
            elif features['avg_temperature'] > 35 or features['avg_temperature'] < 10:
                temp_factor = 0.6
            
            # 水分影响
            moisture_factor = 1.0
            if 50 <= features['avg_soil_moisture'] <= 70:
                moisture_factor = 1.15
            elif features['avg_soil_moisture'] < 25:
                moisture_factor = 0.5
            
            # pH影响
            ph_factor = 1.0
            if 6.0 <= features['avg_ph'] <= 7.0:
                ph_factor = 1.1
            elif features['avg_ph'] < 5.0 or features['avg_ph'] > 8.5:
                ph_factor = 0.7
            
            # 营养影响
            nutrition_factor = (features['avg_nitrogen'] / 30 + 
                              features['avg_phosphorus'] / 15 + 
                              features['avg_potassium'] / 25) / 3
            nutrition_factor = max(0.5, min(1.3, nutrition_factor))
            
            # 光照影响
            light_factor = min(1.2, features['avg_light_intensity'] / 50000)
            
            # 管理影响
            management_factor = 1.0 + (features['irrigation_frequency'] / 100) + (features['fertilizer_applications'] / 50)
            management_factor = min(1.3, management_factor)
            
            # 计算最终产量
            yield_value = (base_yield * temp_factor * moisture_factor * 
                          ph_factor * nutrition_factor * light_factor * management_factor)
            
            # 添加随机噪声
            yield_value *= random.uniform(0.8, 1.2)
            
            features['yield'] = max(20, yield_value)  # 最低产量20kg/亩
            training_data.append(features)
        
        return training_data
    
    def train(self, training_data: List[Dict] = None) -> bool:
        """训练模型"""
        try:
            if training_data is None:
                training_data = self.generate_training_data()
            
            # 准备特征和目标变量
            X = []
            y = []
            
            for sample in training_data:
                features = [sample[name] for name in self.feature_names]
                X.append(features)
                y.append(sample['yield'])
            
            X = np.array(X)
            y = np.array(y)
            
            # 标准化特征
            X_scaled = self.scaler.fit_transform(X)
            
            # 训练模型
            self.model.fit(X_scaled, y)
            self.is_trained = True
            
            # 记录训练历史
            self.training_history.append({
                'timestamp': datetime.now(),
                'training_samples': len(training_data),
                'feature_importance': dict(zip(self.feature_names, self.model.feature_importances_))
            })
            
            return True
            
        except Exception as e:
            print(f"训练产量预测模型失败: {e}")
            return False
    
    def predict(self, input_data: Dict) -> PredictionResult:
        """预测产量"""
        if not self.is_trained:
            return PredictionResult(
                model_name=self.name,
                prediction_type="yield",
                value=0,
                confidence=0,
                probability_distribution=None,
                explanation="模型尚未训练",
                timestamp=datetime.now(),
                input_features=input_data
            )
        
        try:
            # 准备输入特征
            features = [input_data.get(name, 0) for name in self.feature_names]
            X = np.array([features])
            X_scaled = self.scaler.transform(X)
            
            # 预测
            prediction = self.model.predict(X_scaled)[0]
            
            # 计算置信度（基于特征重要性和数据质量）
            feature_importance = self.model.feature_importances_
            data_quality = sum(1 for f in features if f > 0) / len(features)
            confidence = min(0.95, data_quality * 0.8 + 0.2)
            
            # 生成解释
            important_features = sorted(
                zip(self.feature_names, features, feature_importance),
                key=lambda x: x[2], reverse=True
            )[:3]
            
            explanation = f"预测产量: {prediction:.1f} kg/亩。主要影响因素："
            for name, value, importance in important_features:
                explanation += f" {name}({value:.1f}, 重要性{importance:.2f})"
            
            return PredictionResult(
                model_name=self.name,
                prediction_type="yield",
                value=prediction,
                confidence=confidence,
                probability_distribution=None,
                explanation=explanation,
                timestamp=datetime.now(),
                input_features=input_data
            )
            
        except Exception as e:
            return PredictionResult(
                model_name=self.name,
                prediction_type="yield",
                value=0,
                confidence=0,
                probability_distribution=None,
                explanation=f"预测失败: {str(e)}",
                timestamp=datetime.now(),
                input_features=input_data
            )
    
    def evaluate(self, test_data: List[Dict]) -> ModelMetrics:
        """评估模型"""
        if not self.is_trained or not test_data:
            return ModelMetrics(
                model_name=self.name,
                accuracy=0, precision=0, recall=0, f1_score=0,
                rmse=0, mae=0, training_samples=0,
                last_updated=datetime.now()
            )
        
        try:
            # 准备测试数据
            X_test = []
            y_test = []
            
            for sample in test_data:
                features = [sample[name] for name in self.feature_names]
                X_test.append(features)
                y_test.append(sample['yield'])
            
            X_test = np.array(X_test)
            y_test = np.array(y_test)
            X_test_scaled = self.scaler.transform(X_test)
            
            # 预测
            y_pred = self.model.predict(X_test_scaled)
            
            # 计算指标
            rmse = np.sqrt(mean_squared_error(y_test, y_pred))
            mae = np.mean(np.abs(y_test - y_pred))
            
            # 对于回归任务，计算R²作为准确率
            from sklearn.metrics import r2_score
            accuracy = max(0, r2_score(y_test, y_pred))
            
            return ModelMetrics(
                model_name=self.name,
                accuracy=accuracy,
                precision=accuracy,  # 对于回归任务
                recall=accuracy,
                f1_score=accuracy,
                rmse=rmse,
                mae=mae,
                training_samples=len(test_data),
                last_updated=datetime.now()
            )
            
        except Exception as e:
            print(f"评估模型失败: {e}")
            return ModelMetrics(
                model_name=self.name,
                accuracy=0, precision=0, recall=0, f1_score=0,
                rmse=0, mae=0, training_samples=0,
                last_updated=datetime.now()
            )

class DiseaseRiskPredictor(BaseAIModel):
    """病害风险预测模型"""
    
    def __init__(self):
        super().__init__("病害风险预测")
        self.model = RandomForestClassifier(n_estimators=100, random_state=42)
        self.scaler = StandardScaler()
        self.feature_names = [
            'temperature', 'humidity', 'rainfall', 'wind_speed',
            'leaf_wetness_hours', 'soil_moisture', 'ph_value',
            'crop_age_days', 'plant_density', 'previous_disease_history'
        ]
        self.disease_types = ['健康', '真菌病害', '细菌病害', '病毒病害', '营养缺乏']
    
    def generate_training_data(self, num_samples: int = 2000) -> List[Dict]:
        """生成训练数据"""
        training_data = []
        
        for _ in range(num_samples):
            features = {
                'temperature': random.uniform(10, 40),
                'humidity': random.uniform(30, 95),
                'rainfall': random.uniform(0, 50),
                'wind_speed': random.uniform(0, 15),
                'leaf_wetness_hours': random.uniform(0, 24),
                'soil_moisture': random.uniform(20, 90),
                'ph_value': random.uniform(5.0, 8.5),
                'crop_age_days': random.randint(1, 120),
                'plant_density': random.uniform(0.5, 2.0),
                'previous_disease_history': random.randint(0, 5)
            }
            
            # 基于环境条件计算病害风险
            disease_risk = 0
            
            # 真菌病害风险
            if (features['humidity'] > 80 and features['temperature'] > 20 and 
                features['leaf_wetness_hours'] > 6):
                disease_risk += 0.4
                disease_type = '真菌病害'
            
            # 细菌病害风险
            elif (features['humidity'] > 85 and features['rainfall'] > 10 and 
                  features['wind_speed'] < 3):
                disease_risk += 0.3
                disease_type = '细菌病害'
            
            # 病毒病害风险
            elif features['temperature'] > 30 and features['previous_disease_history'] > 2:
                disease_risk += 0.2
                disease_type = '病毒病害'
            
            # 营养缺乏
            elif (features['ph_value'] < 5.5 or features['ph_value'] > 7.5 or 
                  features['soil_moisture'] < 30):
                disease_risk += 0.25
                disease_type = '营养缺乏'
            
            else:
                disease_type = '健康'
            
            # 添加随机因素
            if random.random() < disease_risk:
                features['disease_type'] = disease_type
            else:
                features['disease_type'] = '健康'
            
            training_data.append(features)
        
        return training_data
    
    def train(self, training_data: List[Dict] = None) -> bool:
        """训练模型"""
        try:
            if training_data is None:
                training_data = self.generate_training_data()
            
            # 准备特征和标签
            X = []
            y = []
            
            for sample in training_data:
                features = [sample[name] for name in self.feature_names]
                X.append(features)
                y.append(sample['disease_type'])
            
            X = np.array(X)
            
            # 标准化特征
            X_scaled = self.scaler.fit_transform(X)
            
            # 训练模型
            self.model.fit(X_scaled, y)
            self.is_trained = True
            
            # 记录训练历史
            self.training_history.append({
                'timestamp': datetime.now(),
                'training_samples': len(training_data),
                'classes': self.model.classes_.tolist(),
                'feature_importance': dict(zip(self.feature_names, self.model.feature_importances_))
            })
            
            return True
            
        except Exception as e:
            print(f"训练病害预测模型失败: {e}")
            return False
    
    def predict(self, input_data: Dict) -> PredictionResult:
        """预测病害风险"""
        if not self.is_trained:
            return PredictionResult(
                model_name=self.name,
                prediction_type="disease_risk",
                value="未知",
                confidence=0,
                probability_distribution=None,
                explanation="模型尚未训练",
                timestamp=datetime.now(),
                input_features=input_data
            )
        
        try:
            # 准备输入特征
            features = [input_data.get(name, 0) for name in self.feature_names]
            X = np.array([features])
            X_scaled = self.scaler.transform(X)
            
            # 预测
            prediction = self.model.predict(X_scaled)[0]
            probabilities = self.model.predict_proba(X_scaled)[0]
            
            # 构建概率分布
            prob_dict = dict(zip(self.model.classes_, probabilities))
            confidence = max(probabilities)
            
            # 生成解释
            if prediction == '健康':
                explanation = "当前环境条件下病害风险较低，建议继续保持良好的管理措施。"
            else:
                explanation = f"检测到{prediction}风险，置信度{confidence:.2f}。建议："
                if prediction == '真菌病害':
                    explanation += "降低湿度，改善通风，考虑施用杀菌剂。"
                elif prediction == '细菌病害':
                    explanation += "避免叶面湿润，加强排水，使用铜制剂防治。"
                elif prediction == '病毒病害':
                    explanation += "控制传播媒介，移除感染植株，加强检疫。"
                elif prediction == '营养缺乏':
                    explanation += "调节土壤pH值，补充相应营养元素。"
            
            return PredictionResult(
                model_name=self.name,
                prediction_type="disease_risk",
                value=prediction,
                confidence=confidence,
                probability_distribution=prob_dict,
                explanation=explanation,
                timestamp=datetime.now(),
                input_features=input_data
            )
            
        except Exception as e:
            return PredictionResult(
                model_name=self.name,
                prediction_type="disease_risk",
                value="预测失败",
                confidence=0,
                probability_distribution=None,
                explanation=f"预测失败: {str(e)}",
                timestamp=datetime.now(),
                input_features=input_data
            )
    
    def evaluate(self, test_data: List[Dict]) -> ModelMetrics:
        """评估模型"""
        if not self.is_trained or not test_data:
            return ModelMetrics(
                model_name=self.name,
                accuracy=0, precision=0, recall=0, f1_score=0,
                rmse=0, mae=0, training_samples=0,
                last_updated=datetime.now()
            )
        
        try:
            # 准备测试数据
            X_test = []
            y_test = []
            
            for sample in test_data:
                features = [sample[name] for name in self.feature_names]
                X_test.append(features)
                y_test.append(sample['disease_type'])
            
            X_test = np.array(X_test)
            X_test_scaled = self.scaler.transform(X_test)
            
            # 预测
            y_pred = self.model.predict(X_test_scaled)
            
            # 计算指标
            from sklearn.metrics import precision_score, recall_score, f1_score
            
            accuracy = accuracy_score(y_test, y_pred)
            precision = precision_score(y_test, y_pred, average='weighted', zero_division=0)
            recall = recall_score(y_test, y_pred, average='weighted', zero_division=0)
            f1 = f1_score(y_test, y_pred, average='weighted', zero_division=0)
            
            return ModelMetrics(
                model_name=self.name,
                accuracy=accuracy,
                precision=precision,
                recall=recall,
                f1_score=f1,
                rmse=0,  # 不适用于分类任务
                mae=0,
                training_samples=len(test_data),
                last_updated=datetime.now()
            )
            
        except Exception as e:
            print(f"评估模型失败: {e}")
            return ModelMetrics(
                model_name=self.name,
                accuracy=0, precision=0, recall=0, f1_score=0,
                rmse=0, mae=0, training_samples=0,
                last_updated=datetime.now()
            )

class IrrigationOptimizer(BaseAIModel):
    """智能灌溉优化模型"""
    
    def __init__(self):
        super().__init__("智能灌溉优化")
        self.model = RandomForestRegressor(n_estimators=100, random_state=42)
        self.scaler = StandardScaler()
        self.feature_names = [
            'current_soil_moisture', 'target_soil_moisture', 'soil_type',
            'crop_type', 'growth_stage', 'temperature', 'humidity',
            'wind_speed', 'solar_radiation', 'rainfall_forecast_24h',
            'evapotranspiration_rate', 'field_capacity', 'wilting_point'
        ]
    
    def generate_training_data(self, num_samples: int = 1500) -> List[Dict]:
        """生成训练数据"""
        training_data = []
        
        for _ in range(num_samples):
            features = {
                'current_soil_moisture': random.uniform(20, 80),
                'target_soil_moisture': random.uniform(60, 80),
                'soil_type': random.randint(1, 5),  # 1-5代表不同土壤类型
                'crop_type': random.randint(1, 10),  # 1-10代表不同作物
                'growth_stage': random.randint(1, 5),  # 1-5代表生长阶段
                'temperature': random.uniform(15, 35),
                'humidity': random.uniform(40, 90),
                'wind_speed': random.uniform(0, 10),
                'solar_radiation': random.uniform(100, 800),
                'rainfall_forecast_24h': random.uniform(0, 20),
                'evapotranspiration_rate': random.uniform(2, 8),
                'field_capacity': random.uniform(25, 35),
                'wilting_point': random.uniform(10, 20)
            }
            
            # 计算最优灌溉量
            moisture_deficit = max(0, features['target_soil_moisture'] - features['current_soil_moisture'])
            
            # 基础灌溉量
            base_irrigation = moisture_deficit * 0.5  # mm
            
            # 环境调整因子
            temp_factor = 1.0 + (features['temperature'] - 25) * 0.02
            humidity_factor = 1.0 - (features['humidity'] - 50) * 0.005
            wind_factor = 1.0 + features['wind_speed'] * 0.01
            
            # 作物和生长阶段因子
            crop_factor = 0.8 + features['crop_type'] * 0.04
            stage_factor = 0.6 + features['growth_stage'] * 0.1
            
            # 土壤因子
            soil_factor = 0.8 + features['soil_type'] * 0.05
            
            # 考虑降雨预报
            rain_reduction = min(base_irrigation * 0.8, features['rainfall_forecast_24h'])
            
            # 计算最终灌溉量
            optimal_irrigation = (base_irrigation * temp_factor * humidity_factor * 
                                wind_factor * crop_factor * stage_factor * soil_factor - rain_reduction)
            
            optimal_irrigation = max(0, optimal_irrigation)
            features['optimal_irrigation_mm'] = optimal_irrigation
            
            training_data.append(features)
        
        return training_data
    
    def train(self, training_data: List[Dict] = None) -> bool:
        """训练模型"""
        try:
            if training_data is None:
                training_data = self.generate_training_data()
            
            # 准备特征和目标变量
            X = []
            y = []
            
            for sample in training_data:
                features = [sample[name] for name in self.feature_names]
                X.append(features)
                y.append(sample['optimal_irrigation_mm'])
            
            X = np.array(X)
            y = np.array(y)
            
            # 标准化特征
            X_scaled = self.scaler.fit_transform(X)
            
            # 训练模型
            self.model.fit(X_scaled, y)
            self.is_trained = True
            
            # 记录训练历史
            self.training_history.append({
                'timestamp': datetime.now(),
                'training_samples': len(training_data),
                'feature_importance': dict(zip(self.feature_names, self.model.feature_importances_))
            })
            
            return True
            
        except Exception as e:
            print(f"训练灌溉优化模型失败: {e}")
            return False
    
    def predict(self, input_data: Dict) -> PredictionResult:
        """预测最优灌溉量"""
        if not self.is_trained:
            return PredictionResult(
                model_name=self.name,
                prediction_type="irrigation_amount",
                value=0,
                confidence=0,
                probability_distribution=None,
                explanation="模型尚未训练",
                timestamp=datetime.now(),
                input_features=input_data
            )
        
        try:
            # 准备输入特征
            features = [input_data.get(name, 0) for name in self.feature_names]
            X = np.array([features])
            X_scaled = self.scaler.transform(X)
            
            # 预测
            prediction = self.model.predict(X_scaled)[0]
            
            # 计算置信度
            feature_importance = self.model.feature_importances_
            data_completeness = sum(1 for f in features if f > 0) / len(features)
            confidence = min(0.95, data_completeness * 0.9 + 0.1)
            
            # 生成解释
            current_moisture = input_data.get('current_soil_moisture', 0)
            target_moisture = input_data.get('target_soil_moisture', 70)
            
            explanation = f"建议灌溉量: {prediction:.1f}mm。"
            
            if prediction < 5:
                explanation += "当前土壤湿度适宜，无需灌溉或少量补水。"
            elif prediction < 15:
                explanation += "需要适量灌溉以维持土壤湿度。"
            else:
                explanation += "土壤缺水严重，需要充分灌溉。"
            
            # 添加环境因素说明
            temp = input_data.get('temperature', 25)
            rain_forecast = input_data.get('rainfall_forecast_24h', 0)
            
            if temp > 30:
                explanation += " 高温天气增加了水分需求。"
            if rain_forecast > 5:
                explanation += f" 预计24小时内降雨{rain_forecast:.1f}mm，已考虑在内。"
            
            return PredictionResult(
                model_name=self.name,
                prediction_type="irrigation_amount",
                value=prediction,
                confidence=confidence,
                probability_distribution=None,
                explanation=explanation,
                timestamp=datetime.now(),
                input_features=input_data
            )
            
        except Exception as e:
            return PredictionResult(
                model_name=self.name,
                prediction_type="irrigation_amount",
                value=0,
                confidence=0,
                probability_distribution=None,
                explanation=f"预测失败: {str(e)}",
                timestamp=datetime.now(),
                input_features=input_data
            )
    
    def evaluate(self, test_data: List[Dict]) -> ModelMetrics:
        """评估模型"""
        if not self.is_trained or not test_data:
            return ModelMetrics(
                model_name=self.name,
                accuracy=0, precision=0, recall=0, f1_score=0,
                rmse=0, mae=0, training_samples=0,
                last_updated=datetime.now()
            )
        
        try:
            # 准备测试数据
            X_test = []
            y_test = []
            
            for sample in test_data:
                features = [sample[name] for name in self.feature_names]
                X_test.append(features)
                y_test.append(sample['optimal_irrigation_mm'])
            
            X_test = np.array(X_test)
            y_test = np.array(y_test)
            X_test_scaled = self.scaler.transform(X_test)
            
            # 预测
            y_pred = self.model.predict(X_test_scaled)
            
            # 计算指标
            rmse = np.sqrt(mean_squared_error(y_test, y_pred))
            mae = np.mean(np.abs(y_test - y_pred))
            
            # 计算R²作为准确率
            from sklearn.metrics import r2_score
            accuracy = max(0, r2_score(y_test, y_pred))
            
            return ModelMetrics(
                model_name=self.name,
                accuracy=accuracy,
                precision=accuracy,
                recall=accuracy,
                f1_score=accuracy,
                rmse=rmse,
                mae=mae,
                training_samples=len(test_data),
                last_updated=datetime.now()
            )
            
        except Exception as e:
            print(f"评估模型失败: {e}")
            return ModelMetrics(
                model_name=self.name,
                accuracy=0, precision=0, recall=0, f1_score=0,
                rmse=0, mae=0, training_samples=0,
                last_updated=datetime.now()
            )

class EnvironmentPredictor(BaseAIModel):
    """环境参数预测模型"""
    
    def __init__(self):
        super().__init__("环境参数预测")
        self.models = {
            'temperature': LinearRegression(),
            'humidity': LinearRegression(),
            'soil_moisture': LinearRegression()
        }
        self.scalers = {
            'temperature': StandardScaler(),
            'humidity': StandardScaler(),
            'soil_moisture': StandardScaler()
        }
        self.sequence_length = 24  # 使用24小时的历史数据
        self.prediction_horizon = 6  # 预测未来6小时
    
    def prepare_time_series_data(self, historical_data: List[Dict], target_param: str) -> Tuple[np.ndarray, np.ndarray]:
        """准备时间序列数据"""
        if len(historical_data) < self.sequence_length + self.prediction_horizon:
            return None, None
        
        X, y = [], []
        
        for i in range(len(historical_data) - self.sequence_length - self.prediction_horizon + 1):
            # 输入序列
            sequence = []
            for j in range(i, i + self.sequence_length):
                sequence.extend([
                    historical_data[j].get('air_temperature', 25),
                    historical_data[j].get('air_humidity', 60),
                    historical_data[j].get('soil_moisture', 50),
                    historical_data[j].get('pressure', 1013),
                    historical_data[j].get('wind_speed', 3)
                ])
            X.append(sequence)
            
            # 目标值（未来几小时的平均值）
            future_values = []
            for j in range(i + self.sequence_length, i + self.sequence_length + self.prediction_horizon):
                future_values.append(historical_data[j].get(target_param, 0))
            y.append(np.mean(future_values))
        
        return np.array(X), np.array(y)
    
    def generate_time_series_data(self, num_days: int = 30) -> List[Dict]:
        """生成时间序列数据"""
        data = []
        base_time = datetime.now() - timedelta(days=num_days)
        
        # 初始值
        temp = 25
        humidity = 60
        moisture = 50
        pressure = 1013
        wind = 3
        
        for i in range(num_days * 24):  # 每小时一个数据点
            current_time = base_time + timedelta(hours=i)
            hour = current_time.hour
            
            # 日夜循环
            day_factor = 0.5 + 0.5 * np.sin((hour - 6) * np.pi / 12)
            
            # 添加趋势和随机波动
            temp += random.gauss(0, 0.5) + (day_factor - 0.5) * 2
            temp = np.clip(temp, 10, 40)
            
            humidity += random.gauss(0, 2) + (0.5 - day_factor) * 5
            humidity = np.clip(humidity, 30, 95)
            
            moisture += random.gauss(0, 1) - 0.1  # 缓慢下降
            moisture = np.clip(moisture, 20, 80)
            
            pressure += random.gauss(0, 1)
            pressure = np.clip(pressure, 990, 1030)
            
            wind += random.gauss(0, 0.5)
            wind = np.clip(wind, 0, 15)
            
            data.append({
                'timestamp': current_time.isoformat(),
                'air_temperature': temp,
                'air_humidity': humidity,
                'soil_moisture': moisture,
                'pressure': pressure,
                'wind_speed': wind
            })
        
        return data
    
    def train(self, training_data: List[Dict] = None) -> bool:
        """训练模型"""
        try:
            if training_data is None:
                training_data = self.generate_time_series_data()
            
            for param in ['air_temperature', 'air_humidity', 'soil_moisture']:
                # 准备数据
                X, y = self.prepare_time_series_data(training_data, param)
                
                if X is None or len(X) == 0:
                    continue
                
                # 标准化
                X_scaled = self.scalers[param.split('_')[1]].fit_transform(X)
                
                # 训练模型
                self.models[param.split('_')[1]].fit(X_scaled, y)
            
            self.is_trained = True
            
            # 记录训练历史
            self.training_history.append({
                'timestamp': datetime.now(),
                'training_samples': len(training_data),
                'sequence_length': self.sequence_length,
                'prediction_horizon': self.prediction_horizon
            })
            
            return True
            
        except Exception as e:
            print(f"训练环境预测模型失败: {e}")
            return False
    
    def predict(self, input_data: Dict) -> PredictionResult:
        """预测环境参数"""
        if not self.is_trained:
            return PredictionResult(
                model_name=self.name,
                prediction_type="environment",
                value={},
                confidence=0,
                probability_distribution=None,
                explanation="模型尚未训练",
                timestamp=datetime.now(),
                input_features=input_data
            )
        
        try:
            # 从输入数据构建序列（简化版本）
            historical_sequence = input_data.get('historical_sequence', [])
            
            if len(historical_sequence) < self.sequence_length:
                # 如果历史数据不足，使用当前值填充
                current_values = [
                    input_data.get('air_temperature', 25),
                    input_data.get('air_humidity', 60),
                    input_data.get('soil_moisture', 50),
                    input_data.get('pressure', 1013),
                    input_data.get('wind_speed', 3)
                ]
                sequence = current_values * self.sequence_length
            else:
                # 使用实际历史数据
                sequence = []
                for data_point in historical_sequence[-self.sequence_length:]:
                    sequence.extend([
                        data_point.get('air_temperature', 25),
                        data_point.get('air_humidity', 60),
                        data_point.get('soil_moisture', 50),
                        data_point.get('pressure', 1013),
                        data_point.get('wind_speed', 3)
                    ])
            
            X = np.array([sequence])
            
            predictions = {}
            for param in ['temperature', 'humidity', 'soil_moisture']:
                if param in self.models:
                    X_scaled = self.scalers[param].transform(X)
                    pred = self.models[param].predict(X_scaled)[0]
                    predictions[f'predicted_{param}'] = pred
            
            confidence = 0.75  # 基础置信度
            
            explanation = f"未来{self.prediction_horizon}小时环境预测："
            for param, value in predictions.items():
                explanation += f" {param}: {value:.1f}"
            
            return PredictionResult(
                model_name=self.name,
                prediction_type="environment",
                value=predictions,
                confidence=confidence,
                probability_distribution=None,
                explanation=explanation,
                timestamp=datetime.now(),
                input_features=input_data
            )
            
        except Exception as e:
            return PredictionResult(
                model_name=self.name,
                prediction_type="environment",
                value={},
                confidence=0,
                probability_distribution=None,
                explanation=f"预测失败: {str(e)}",
                timestamp=datetime.now(),
                input_features=input_data
            )
    
    def evaluate(self, test_data: List[Dict]) -> ModelMetrics:
        """评估模型"""
        # 简化的评估实现
        return ModelMetrics(
            model_name=self.name,
            accuracy=0.8,  # 模拟值
            precision=0.8,
            recall=0.8,
            f1_score=0.8,
            rmse=2.5,
            mae=1.8,
            training_samples=len(test_data) if test_data else 0,
            last_updated=datetime.now()
        )

class AIModelManager:
    """AI模型管理器"""
    
    def __init__(self, models_dir: str = "models"):
        self.models_dir = models_dir
        self.models = {}
        self.prediction_history = deque(maxlen=1000)
        
        # 确保模型目录存在
        os.makedirs(models_dir, exist_ok=True)
        
        # 初始化所有模型
        self.initialize_models()
    
    def initialize_models(self):
        """初始化所有模型"""
        self.models = {
            'yield_predictor': CropYieldPredictor(),
            'disease_predictor': DiseaseRiskPredictor(),
            'irrigation_optimizer': IrrigationOptimizer(),
            'environment_predictor': EnvironmentPredictor()
        }
        
        # 尝试加载已训练的模型
        for name, model in self.models.items():
            model_path = os.path.join(self.models_dir, f"{name}.joblib")
            if os.path.exists(model_path):
                model.load_model(model_path)
                print(f"✅ 已加载模型: {name}")
            else:
                # 训练新模型
                print(f"🔄 训练新模型: {name}")
                if model.train():
                    model.save_model(model_path)
                    print(f"✅ 模型训练完成: {name}")
                else:
                    print(f"❌ 模型训练失败: {name}")
    
    def get_model(self, model_name: str) -> Optional[BaseAIModel]:
        """获取模型"""
        return self.models.get(model_name)
    
    def predict_with_model(self, model_name: str, input_data: Dict) -> Optional[PredictionResult]:
        """使用指定模型进行预测"""
        model = self.get_model(model_name)
        if model:
            result = model.predict(input_data)
            self.prediction_history.append(result)
            return result
        return None
    
    def get_all_predictions(self, input_data: Dict) -> Dict[str, PredictionResult]:
        """使用所有模型进行预测"""
        results = {}
        for name, model in self.models.items():
            try:
                result = model.predict(input_data)
                results[name] = result
                self.prediction_history.append(result)
            except Exception as e:
                print(f"模型 {name} 预测失败: {e}")
        
        return results
    
    def evaluate_all_models(self) -> Dict[str, ModelMetrics]:
        """评估所有模型"""
        metrics = {}
        for name, model in self.models.items():
            try:
                # 生成测试数据
                if hasattr(model, 'generate_training_data'):
                    test_data = model.generate_training_data(200)  # 生成200个测试样本
                    metrics[name] = model.evaluate(test_data)
                else:
                    metrics[name] = model.evaluate([])
            except Exception as e:
                print(f"评估模型 {name} 失败: {e}")
        
        return metrics
    
    def retrain_model(self, model_name: str, training_data: List[Dict] = None) -> bool:
        """重新训练模型"""
        model = self.get_model(model_name)
        if model:
            if model.train(training_data):
                model_path = os.path.join(self.models_dir, f"{model_name}.joblib")
                return model.save_model(model_path)
        return False
    
    def get_prediction_history(self, model_name: str = None, limit: int = 100) -> List[PredictionResult]:
        """获取预测历史"""
        if model_name:
            filtered_history = [r for r in self.prediction_history if r.model_name == model_name]
            return list(filtered_history)[-limit:]
        else:
            return list(self.prediction_history)[-limit:]
    
    def get_model_status(self) -> Dict[str, Dict]:
        """获取所有模型状态"""
        status = {}
        for name, model in self.models.items():
            status[name] = {
                'name': model.name,
                'is_trained': model.is_trained,
                'training_history_count': len(model.training_history),
                'last_training': model.training_history[-1]['timestamp'].isoformat() if model.training_history else None
            }
        return status

# 测试函数
def test_ai_models():
    """测试AI模型功能"""
    print("🧠 测试AI模型和预测算法...")
    
    # 创建模型管理器
    manager = AIModelManager()
    
    # 测试输入数据
    test_input = {
        'avg_temperature': 26.5,
        'avg_humidity': 70,
        'avg_soil_moisture': 55,
        'avg_ph': 6.8,
        'avg_nitrogen': 25,
        'avg_phosphorus': 15,
        'avg_potassium': 30,
        'total_rainfall': 50,
        'avg_light_intensity': 45000,
        'growth_days': 80,
        'irrigation_frequency': 15,
        'fertilizer_applications': 3,
        'current_soil_moisture': 45,
        'target_soil_moisture': 65,
        'temperature': 28,
        'humidity': 75,
        'rainfall': 5,
        'wind_speed': 3,
        'leaf_wetness_hours': 8,
        'crop_age_days': 60,
        'plant_density': 1.2,
        'previous_disease_history': 1
    }
    
    # 测试所有模型预测
    results = manager.get_all_predictions(test_input)
    
    print("\n📊 预测结果:")
    for model_name, result in results.items():
        print(f"\n{model_name}:")
        print(f"  预测值: {result.value}")
        print(f"  置信度: {result.confidence:.2f}")
        print(f"  说明: {result.explanation}")
    
    # 评估模型性能
    print("\n📈 模型性能评估:")
    metrics = manager.evaluate_all_models()
    for model_name, metric in metrics.items():
        print(f"\n{model_name}:")
        print(f"  准确率: {metric.accuracy:.3f}")
        print(f"  RMSE: {metric.rmse:.3f}")
        print(f"  MAE: {metric.mae:.3f}")
    
    # 显示模型状态
    print("\n⚙️ 模型状态:")
    status = manager.get_model_status()
    for model_name, info in status.items():
        print(f"  {model_name}: {'已训练' if info['is_trained'] else '未训练'}")

if __name__ == "__main__":
    test_ai_models()